// ==============================
// 成员检测的基本概念
// ==============================
在C++模板元编程中, 检测类型是否具有特定成员(成员函数、成员类型或成员变量)是一项常见需求。
成员检测特征(Member Detection Traits)允许我们在编译期确定一个类型是否拥有特定名称的成员, 这对于编写通用代码和实现SFINAE(Substitution Failure Is Not An Error)技术非常重要。


// ===================================
// 检测成员的实现技术
// ===================================

// 1. 基于SFINAE的成员检测
// 最常见的成员检测方法是利用SFINAE原则, 通过尝试使用目标成员并观察替换是否成功来实现。基本模式如下: 
// 主模板声明(假设不存在成员)
template<typename T, typename = void>
struct HasMemberX : std::false_type {};

// 特化版本(当成员存在时)
template<typename T>
struct HasMemberX<T, 
    std::void_t<decltype(std::declval<T>().x)>> : std::true_type {};

// 2. 检测成员函数
// 检测成员函数通常需要考虑函数签名。例如, 检测是否存在size()方法: 
template<typename T, typename = void>
struct HasSizeMethod : std::false_type {};

template<typename T>
struct HasSizeMethod<T, 
    std::void_t<decltype(std::declval<T>().size())>> : std::true_type {};

// 3. 检测成员类型
// 检测嵌套类型(如value_type)的实现(嵌套类型, 参考嵌套类型.cpp): 
template<typename T, typename = void>
struct HasValueType : std::false_type {};

template<typename T>
struct HasValueType<T, 
    std::void_t<typename T::value_type>> : std::true_type {};


// 4. 检测静态成员
// 检测静态成员变量或函数: 
template<typename T, typename = void>
struct HasStaticMember : std::false_type {};

template<typename T>
struct HasStaticMember<T, 
    std::void_t<decltype(T::static_member)>> : std::true_type {};
// 为什么检测静态成员需要使用 decltype
// 在检测静态成员时使用 decltype 是因为静态成员(无论是变量还是函数)都是值或表达式, 而不是类型。decltype 的作用是获取表达式的类型。

// =================================
// 高级成员检测技术
// =================================
// 1. 检测具有特定签名的成员函数
有时我们不仅需要知道成员函数是否存在, 还需要确认其签名是否符合预期: 

// 检测是否有接受int参数并返回bool的foo方法
template<typename T, typename = void>
struct HasFooMethod : std::false_type {};

template<typename T>
struct HasFooMethod<T, 
    std::void_t<decltype(std::declval<T>().foo(std::declval<int>()) == true)>> 
    : std::true_type {};

// 2. 使用表达式SFINAE
更复杂的情况可能需要检测表达式的有效性: 
// 检测是否支持operator[]
template<typename T, typename Index = int, typename = void>
struct HasSubscriptOperator : std::false_type {};

template<typename T, typename Index>
struct HasSubscriptOperator<T, Index,
    std::void_t<decltype(std::declval<T>()[std::declval<Index>()])>> 
    : std::true_type {};


// 3. 检测多个成员的存在
组合多个检测: 
template<typename T>
struct IsContainer {
    static constexpr bool value = 
        HasValueType<T>::value && 
        HasSizeMethod<T>::value && 
        HasBeginMethod<T>::value && 
        HasEndMethod<T>::value;
};

// ==========================
// 实际应用示例
// ==========================
1. 条件编译
利用成员检测实现条件编译: 
template<typename T>
void process(T const& x) {
    if constexpr (HasToStringMethod<T>::value) {
        // 使用toString方法
        std::cout << x.toString();
    } else {
        // 备选方案
        std::cout << x;
    }
}

2. 标签分发
结合标签分发技术: 
template<typename T>
void optimize(T& container) {
    optimize_impl(container, HasReserveMethod<T>());
}

template<typename T>
void optimize_impl(T& container, std::true_type) {
    // 如果有reserve方法, 预先分配空间
    container.reserve(1000);
}

template<typename T>
void optimize_impl(T& container, std::false_type) {
    // 没有reserve方法时的处理
}

3. 特化和重载
基于成员检测进行模板特化: 
template<typename T, bool = HasSerializeMethod<T>::value>
struct Serializer;

template<typename T>
struct Serializer<T, true> {
    static void serialize(T const& obj) {
        obj.serialize();
    }
};

template<typename T>
struct Serializer<T, false> {
    static void serialize(T const& obj) {
        // 默认序列化实现
    }
};

// =======================
// 注意事项与最佳实践
// =======================
1.避免过度检测: 只检测真正需要的成员, 过多的检测会增加编译时间和代码复杂度
2.考虑继承关系: 成员检测不会考虑私有继承的成员, 需要特别注意访问权限
3.C++17简化: C++17引入的std::void_t大大简化了成员检测的实现
4.与concepts的关系: C++20的concepts提供了更强大和表达力更强的约束机制, 可以部分替代传统的成员检测
5.编译错误诊断: 成员检测可能导致复杂的编译错误, 应提供清晰的错误信息
